package view.swing;

import cotroller.event.ChangeGameListener;
import cotroller.event.MovementListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import model.Model;
import model.ModelFactory;
import model.ScoreDB;
import view.View;

/**
 *
 * @author Andrea
 */
public class SwingView extends javax.swing.JFrame implements View {

    private Model model;
    
    @SuppressWarnings("CallToThreadStartDuringObjectConstruction")
    public SwingView(final ModelFactory... fac) {
        initComponents();

        changeGameListeners = new ArrayList<>();

        gameCommands.setEnabledButtons(false);

        Thread a = new Thread(new Runnable() {
            @Override
            public void run() {
                addGames(fac);
            }
        });
        
        a.start();
    }

    @Override
    public void update() {
        gamePanel.refresh();
    }

    @Override
    public void updateScore() {
        scorePanel.updateScore(model.getScore());
    }

    @Override
    public void gameOver() {
        JOptionPane.showMessageDialog(
                this,
                "Game is over you can play another time from File->New Game \n" + "your score is: " + model.getScore() + "points",
                "Game Over!",
                JOptionPane.WARNING_MESSAGE);

        gameCommands.setEnabledButtons(false);

        String username = JOptionPane.showInputDialog(this, "Insert your username for the highscore");

        ScoreDB.submitScore(username, model.getScore());

        highScorePanel.updateScoreList();
    }

    private void addGames(ModelFactory... facs) {
        for (ModelFactory fac : facs) {
            JMenuItem mnit = new JRadioButtonMenuItem();

            mnit.setText(fac.getGameName());

            mnit.addActionListener(new GameMenuActionListener(fac));

            mnit.setSelected(false);

            filemn.add(mnit);

            gamesbtngrp.add(mnit);
            
            if(gamesbtngrp.getSelection() == null){
                mnit.doClick();
            }
        }
    }

    public void addGameFactoryes(ModelFactory... fac) {
        addGames(fac);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        gamesbtngrp = new javax.swing.ButtonGroup();
        gameCommands = new view.swing.GameCommands();
        scorePanel = new view.swing.ScorePanel();
        highScorePanel = new view.swing.HighScorePanel();
        gamePanel = new graphics.swing.DrawingPanel();
        menuBar = new javax.swing.JMenuBar();
        filemn = new javax.swing.JMenu();
        newGamemnit = new javax.swing.JMenuItem();
        javax.swing.JPopupMenu.Separator jSeparator3 = new javax.swing.JPopupMenu.Separator();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new java.awt.Dimension(400, 400));
        addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                formKeyPressed(evt);
            }
        });

        highScorePanel.setFocusable(false);

        javax.swing.GroupLayout gamePanelLayout = new javax.swing.GroupLayout(gamePanel);
        gamePanel.setLayout(gamePanelLayout);
        gamePanelLayout.setHorizontalGroup(
            gamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 0, Short.MAX_VALUE)
        );
        gamePanelLayout.setVerticalGroup(
            gamePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 230, Short.MAX_VALUE)
        );

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("view/swing/Bundle"); // NOI18N
        filemn.setText(bundle.getString("SwingView.filemn.text")); // NOI18N

        newGamemnit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
        newGamemnit.setText(bundle.getString("SwingView.newGamemnit.text")); // NOI18N
        newGamemnit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newGamemnitActionPerformed(evt);
            }
        });
        filemn.add(newGamemnit);
        filemn.add(jSeparator3);

        menuBar.add(filemn);

        setJMenuBar(menuBar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(gameCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(scorePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(gamePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(highScorePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 132, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(highScorePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(scorePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(gamePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(gameCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );

        highScorePanel.updateScoreList();

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void newGamemnitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newGamemnitActionPerformed

        if (gamesbtngrp.getSelection() != null) {
            model.start();

            gameCommands.setEnabledButtons(true);
        }
    }//GEN-LAST:event_newGamemnitActionPerformed

    private void formKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyPressed

        switch (evt.getKeyCode()) {
            case KeyEvent.VK_LEFT:
                gameCommands.clickLeft();
                break;
            case KeyEvent.VK_RIGHT:
                gameCommands.clickRight();
                break;
            case KeyEvent.VK_UP:
                gameCommands.clickUp();
                break;
            case KeyEvent.VK_DOWN:
                gameCommands.clickDown();
                break;
        }
    }//GEN-LAST:event_formKeyPressed

    @Override
    public boolean addMovementListener(MovementListener e) {
        return gameCommands.addMovementListener(e);
    }

    @Override
    public boolean removeMovementListener(MovementListener o) {
        return gameCommands.removeMovementListener(o);
    }

    @Override
    public boolean addChangeGameListener(ChangeGameListener lis) {
        return changeGameListeners.add(lis);
    }

    @Override
    public boolean removeChangeGameListener(ChangeGameListener lis) {
        return changeGameListeners.remove(lis);
    }
    
    private void notifyGameChanged(Model model){
        for (ChangeGameListener cgl : changeGameListeners) {
            cgl.changeGame(model);
        }
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu filemn;
    private view.swing.GameCommands gameCommands;
    private graphics.swing.DrawingPanel gamePanel;
    private javax.swing.ButtonGroup gamesbtngrp;
    private view.swing.HighScorePanel highScorePanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JMenuItem newGamemnit;
    private view.swing.ScorePanel scorePanel;
    // End of variables declaration//GEN-END:variables
    private final List<ChangeGameListener> changeGameListeners;

    private class GameMenuActionListener implements ActionListener {

        private final ModelFactory fac;

        public GameMenuActionListener(ModelFactory fac) {
            this.fac = fac;
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            Model game = fac.createNewGame();
            model = game;

            model.addObserver(SwingView.this);

            gamePanel.clearSurface();
            gamePanel.attach(game);
            gamePanel.refresh();
            
            notifyGameChanged(model);
        }
    }
}
